<!DOCTYPE HTML>
<html>
<head>
  <title>ServiceWorkerRegistration.getNotifications() on main thread and worker thread.</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="text/javascript">

  SimpleTest.requestFlakyTimeout("untriaged");

  function testFrame(src) {
    return new Promise(function(resolve, reject) {
      var iframe = document.createElement("iframe");
      iframe.src = src;
      window.callback = function(result) {
        iframe.src = "about:blank";
        document.body.removeChild(iframe);
        iframe = null;
        SpecialPowers.exactGC(function() {
          resolve(result);
        });
      };
      document.body.appendChild(iframe);
    });
  }

  function registerSW() {
    return testFrame('notification/register.html').then(function() {
      ok(true, "Registered service worker.");
    });
  }

  function unregisterSW() {
    return testFrame('notification/unregister.html').then(function() {
      ok(true, "Unregistered service worker.");
    });
  }

  // To check that the scope is respected when retrieving notifications.
  function registerAlternateSWAndAddNotification() {
    return testFrame('notification_alt/register.html').then(function() {
      ok(true, "Registered alternate service worker.");
      return navigator.serviceWorker.getRegistration("./notification_alt/").then(function(reg) {
        return reg.showNotification("This is a notification_alt");
      });
    });
  }

  function unregisterAlternateSWAndAddNotification() {
    return testFrame('notification_alt/unregister.html').then(function() {
      ok(true, "unregistered alternate service worker.");
    });
  }

  function testDismiss() {
    // Dismissed persistent notifications should be removed from the
    // notification list.
    var alertsService = SpecialPowers.Cc["@mozilla.org/alerts-service;1"]
                                     .getService(SpecialPowers.Ci.nsIAlertsService);
    return navigator.serviceWorker.getRegistration("./notification/")
      .then(function(reg) {
        return reg.showNotification(
          "This is a notification that will be closed", { tag: "dismiss" })
          .then(function() {
            return reg;
          });
      }).then(function(reg) {
        return reg.getNotifications()
          .then(function(notifications) {
            is(notifications.length, 1, "There should be one visible notification");
            is(notifications[0].tag, "dismiss", "Tag should match");

            // Simulate dismissing the notification by using the alerts service
            // directly, instead of `Notification#close`.
            var principal = SpecialPowers.wrap(document).nodePrincipal;
            var id = principal.origin + "#tag:dismiss";
            alertsService.closeAlert(id, principal);

            return reg;
          });
      }).then(function(reg) {
        return reg.getNotifications();
      }).then(function(notifications) {
        // Make sure dismissed notifications are no longer retrieved.
        is(notifications.length, 0, "There should be no more stored notifications");
      });
  }

  function testGet() {
    // Non persistent notifications will not show up in getNotification().
    var n = new Notification("Scope does not match");
    var options = NotificationTest.payload;
    return navigator.serviceWorker.getRegistration("./notification/")
      .then(function(reg) {
        return reg.showNotification("This is a title", options)
                 .then(function() {
                  return reg;
                 });
      }).then(function(reg) {
        return registerAlternateSWAndAddNotification().then(function() {
          return reg;
        });
      }).then(function(reg) {
        return reg.getNotifications();
      }).then(function(notifications) {
        is(notifications.length, 1, "There should be one stored notification");
        var notification = notifications[0];
        ok(notification instanceof Notification, "Should be a Notification");
        is(notification.title, "This is a title", "Title should match");
        for (var key in options) {
          if (key === "data") {
            ok(NotificationTest.customDataMatches(notification.data),
               "data property should match");
            continue;
          }
          is(notification[key], options[key], key + " property should match");
        }
        notification.close();
      }).then(function() {
        return navigator.serviceWorker.getRegistration("./notification/").then(function(reg) {
          return reg.getNotifications();
        });
      }).then(function(notifications) {
        // Make sure closed notifications are no longer retrieved.
        is(notifications.length, 0, "There should be no more stored notifications");
      }).catch(function(e) {
        ok(false, "Something went wrong " + e.message);
      }).then(unregisterAlternateSWAndAddNotification);
  }

  function testGetWorker() {
    todo(false, "navigator.serviceWorker is not available on workers yet");
    return Promise.resolve();
  }

  function waitForSWTests(reg, msg) {
    return new Promise(function(resolve, reject) {
      var content = document.getElementById("content");

      iframe = document.createElement("iframe");

      content.appendChild(iframe);
      iframe.setAttribute('src', "notification/listener.html");

      window.onmessage = function(e) {
        if (e.data.type == 'status') {
          ok(e.data.status, "Service worker test: " + e.data.msg);
        } else if (e.data.type == 'finish') {
          content.removeChild(iframe);
          resolve();
        }
      }

      iframe.onload = function(e) {
        iframe.onload = null;
        reg.active.postMessage(msg);
      }
    });
  }

  function testGetServiceWorker() {
    return navigator.serviceWorker.getRegistration("./notification/")
      .then(function(reg) {
        return waitForSWTests(reg, 'create');
      });
  }

  // Create a Notification here, make sure ServiceWorker sees it.
  function testAcrossThreads() {
    return navigator.serviceWorker.getRegistration("./notification/")
      .then(function(reg) {
        return reg.showNotification("This is a title")
                 .then(function() {
                  return reg;
                 });
      }).then(function(reg) {
        return waitForSWTests(reg, 'do-not-create');
      });
  }

  SimpleTest.waitForExplicitFinish();

  MockServices.register();
  SpecialPowers.pushPrefEnv({"set": [
    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
    ["dom.serviceWorkers.enabled", true],
    ["dom.serviceWorkers.testing.enabled", true],
    ["dom.webnotifications.workers.enabled", true],
    ["dom.webnotifications.serviceworker.enabled", true],
    ["notification.prompt.testing", true],
  ]}, function() {
    registerSW()
      .then(testGet)
      .then(testGetWorker)
      .then(testGetServiceWorker)
      .then(testAcrossThreads)
      .then(testDismiss)
      .then(unregisterSW)
      .then(function() {
        MockServices.unregister();
        SimpleTest.finish();
      });
  });
</script>
</body>
</html>
